<?php
// $Id: common.inc 27 2010-11-16 12:49:54Z mjohnson60@gmail.com $
//
// $Author: mjohnson60@gmail.com $
// $Date: 2010-11-16 12:49:54 +0000 (Tue, 16 Nov 2010) $
// 
// $Rev: 27 $
//

/**
 * Start the timer with the specified name. If you start and stop
 * the same timer multiple times, the measured intervals will be
 * accumulated.
 *
 * @param name
 * The name of the timer.
 */
function timer_start($name)
{
	global $timers;
	
	list($usec, $sec) = explode(' ', microtime());
	$timers[$name]['start'] = (float) $usec + (float) $sec;
	$timers[$name]['count'] = isset($timers[$name]['count']) ? ++$timers[$name]['count'] : 1;
}

/**
 * Read the current timer value without stopping the timer.
 *
 * @param name
 * The name of the timer.
 * @return
 * The current timer value in ms.
 */
function timer_read($name)
{
	global $timers;
	
	if (isset($timers[$name]['start']))
	{
		list($usec, $sec) = explode(' ', microtime());
		$stop = (float) $usec + (float) $sec;
		$diff = round(($stop - $timers[$name]['start']) * 1000, 2);
		
		if (isset($timers[$name]['time']))
		{
			$diff += $timers[$name]['time'];
		}
		return $diff;
	}
}

/**
 * Stop the timer with the specified name.
 *
 * @param name
 * The name of the timer.
 * @return
 * A timer array. The array contains the number of times the
 * timer has been started and stopped (count) and the accumulated
 * timer value in ms (time).
 */
function timer_stop($name)
{
	global $timers;
	
	$timers[$name]['time'] = timer_read($name);
	unset($timers[$name]['start']);
	
	return $timers[$name];
}

/**
 * Ensure the private key variable used to generate tokens is set.
 *
 * @return
 *   The private key.
 */
function get_private_key()
{
	if (!($key = Storage::get('athena_private_key', 0)))
	{
		$key = md5(uniqid(mt_rand(), true)) . md5(uniqid(mt_rand(), true));
		Storage::set('athena_private_key', $key);
	}
	
	return $key;
}

/**
 * Generate a token based on $value, the current user session and private key.
 *
 * @param $value
 *   An additional value to base the token on.
 */
function get_token($value = '')
{
	$private_key = get_private_key();
	return md5(session_id() . $value . $private_key);
}

/**
 * parse_info_file()
 * 
 * Enter description here ...
 * 
 * @param string $filename
 * @param string $name
 * @return array
 */
function parse_info_file($filename, $name) 
{
	static $defaults = array(
		'dependencies' => array(), 
		'dependents' => array(), 
		'description' => '', 
		'version' => -1, 
		'php' => DRUPAL_MINIMUM_PHP
	);
	
	$config = array($name => array());
	
	include('./' . $filename);
	
	$config[$name] = $config[$name] + $defaults;
	
	return $config[$name];
}

/**
 * maintenance_theme()
 * 
 * Enter description here ...
 * 
 */
function maintenance_theme()
{
	require_once('./includes/theme.maintenance.inc');
	_maintenance_theme();
}

/**
 * Validate a token based on $value, the current user session and private key.
 *
 * @param $token
 *   The token to be validated.
 * @param $value
 *   An additional value to base the token on.
 * @param $skip_anonymous
 *   Set to true to skip token validation for anonymous users.
 * @return
 *   True for a valid token, false for an invalid token. When $skip_anonymous
 *   is true, the return value will always be true for anonymous users.
 */
function valid_token($token, $value = '', $skip_anonymous = FALSE)
{
	global $user;
	return (($skip_anonymous && $user->uid == 0) || ($token == md5(session_id() . $value . Storage::get('athena_private_key', ''))));
}

/**
 * render_unique_id()
 * 
 * Guarantee a unique ID for the page element the page
 * 
 * This function is only useful if everytime an HTML id is used, that id
 * is checked through this function before rendering
 * 
 * @param mixed $id
 * @return
 */
function unique_id($id)
{
	static $built_ids = array();
	
	$id = strtr(strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
	$id = preg_replace(array('/[^A-Za-z0-9\-_]/', '/\-+/'), array('', '-'), $id);
	
	if (isset($built_ids[$id]))
	{
		$id = $id . '-' . $built_ids[$id]++;
	}
	else
	{
		$built_ids[$id] = 1;
	}
	
	return $id;
}

/**
 * render_html_class()
 * 
 * Prepare a string for use as a valid class name.
 *
 * @param $class
 * The class name to clean.
 * @return
 * The cleaned class name.
 */
function html_class($class)
{
	return clean_css_identifier(strtolower($class));
}

/**
 * render_clean_css_identifier()
 * 
 * Prepare a string for use as a valid CSS identifier (element, class or ID name).
 *
 * @param $identifier
 * The identifier to clean.
 * @param $filter
 * An array of string replacements to use on the identifier.
 * @return
 * The cleaned identifier.
 */
function clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => ''))
{
	// By default, we filter using Drupal's coding standards.
	$identifier = strtr($identifier, $filter);
	
	// Valid characters in a CSS identifier are:
	// - the hyphen (U+002D)
	// - a-z (U+0030 - U+0039)
	// - A-Z (U+0041 - U+005A)
	// - the underscore (U+005F)
	// - 0-9 (U+0061 - U+007A)
	// - ISO 10646 characters U+00A1 and higher
	// We strip out any character not in the above list.
	$identifier = preg_replace('/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u', '', $identifier);
	
	return $identifier;
}

/**
 *
 * @param <type> $function
 * @param <type> $args
 * @return <type> 
 */
function call_function($function, &$args)
{
	if (function_exists($function))
	{
		return call_user_func_array($function, $args);
	}
	
	return FALSE;
}

/**
 *
 * @param <type> $session
 * @return stdClass 
 */
function anonymous_user($session = '')
{
	$user = new stdClass();
	$user->uid = 0;
	$user->hostname = Athena::ipAddress();
	$user->roles = array(
		USER_ANONYMOUS_RID => 'anonymous'
	);
	$user->session = $session;
	$user->cache = 0;
	return $user;
}

/**
 * Strips dangerous protocols (e.g. 'javascript:') from a URI.
 *
 * This function must be called for all URIs within user-entered input prior
 * to being output to an HTML attribute value. It is often called as part of
 * check_url() or filter_xss(), but those functions return an HTML-encoded
 * string, so this function can be called independently when the output needs to
 * be a plain-text string for passing to t(), l(), drupal_attributes(), or
 * another function that will call check_plain() separately.
 *
 * @param $uri
 *   A plain-text URI that might contain dangerous protocols.
 *
 * @return
 *   A plain-text URI stripped of dangerous protocols. As with all plain-text
 *   strings, this return value must not be output to an HTML page without
 *   check_plain() being called on it. However, it can be passed to functions
 *   expecting plain-text strings.
 *
 * @see check_url()
 */
function strip_dangerous_protocols($uri)
{
	static $allowed_protocols;
	
	if (!isset($allowed_protocols))
	{
		$allowed_protocols = array_flip(Storage::get('filter_allowed_protocols', array('ftp', 'http', 'https', 'irc', 'mailto', 'news', 'nntp', 'rtsp', 'sftp', 'ssh', 'tel', 'telnet', 'webcal')));
	}
	
	// Iteratively remove any invalid protocol found.
	do
	{
		$before = $uri;
		$colonpos = strpos($uri, ':');
		if ($colonpos > 0)
		{
			// We found a colon, possibly a protocol. Verify.
			$protocol = substr($uri, 0, $colonpos);
			// If a colon is preceded by a slash, question mark or hash, it cannot
			// possibly be part of the URL scheme. This must be a relative URL, which
			// inherits the (safe) protocol of the base document.
			if (preg_match('![/?#]!', $protocol))
			{
				break;
			}
			// Check if this is a disallowed protocol. Per RFC2616, section 3.2.3
			// (URI Comparison) scheme comparison must be case-insensitive.
			if (!isset($allowed_protocols[strtolower($protocol)]))
			{
				$uri = substr($uri, $colonpos + 1);
			}
		}
	} while ($before != $uri);
	
	return $uri;
}

/**
 * Generates an internal or external URL.
 *
 * When creating links in modules, consider whether l() could be a better
 * alternative than url().
 *
 * @param $path
 *   The internal path or external URL being linked to, such as "node/34" or
 *   "http://example.com/foo". A few notes:
 *   - If you provide a full URL, it will be considered an external URL.
 *   - If you provide only the path (e.g. "node/34"), it will be
 *     considered an internal link. In this case, it should be a system URL,
 *     and it will be replaced with the alias, if one exists. Additional query
 *     arguments for internal paths must be supplied in $options['query'], not
 *     included in $path.
 *   - If you provide an internal path and $options['alias'] is set to TRUE, the
 *     path is assumed already to be the correct path alias, and the alias is
 *     not looked up.
 *   - The special string '<front>' generates a link to the site's base URL.
 *   - If your external URL contains a query (e.g. http://example.com/foo?a=b),
 *     then you can either URL encode the query keys and values yourself and
 *     include them in $path, or use $options['query'] to let this function
 *     URL encode them.
 * @param $options
 *   An associative array of additional options, with the following elements:
 *   - 'query': An array of query key/value-pairs (without any URL-encoding) to
 *     append to the URL.
 *   - 'fragment': A fragment identifier (named anchor) to append to the URL.
 *     Do not include the leading '#' character.
 *   - 'absolute': Defaults to FALSE. Whether to force the output to be an
 *     absolute link (beginning with http:). Useful for links that will be
 *     displayed outside the site, such as in an RSS feed.
 *   - 'alias': Defaults to FALSE. Whether the given path is a URL alias
 *     already.
 *   - 'external': Whether the given path is an external URL.
 *   - 'language': An optional language object. If the path being linked to is
 *     internal to the site, $options['language'] is used to look up the alias
 *     for the URL. If $options['language'] is omitted, the global $language_url
 *     will be used.
 *   - 'https': Whether this URL should point to a secure location. If not
 *     defined, the current scheme is used, so the user stays on http or https
 *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
 *     only be enforced when the variable 'https' is set to TRUE.
 *   - 'base_url': Only used internally, to modify the base URL when a language
 *     dependent URL requires so.
 *   - 'prefix': Only used internally, to modify the path when a language
 *     dependent URL requires so.
 *   - 'script': The script filename in Drupal's root directory to use when
 *     clean URLs are disabled, such as 'index.php'. Defaults to an empty
 *     string, as most modern web servers automatically find 'index.php'. If
 *     clean URLs are disabled, the value of $path is appended as query
 *     parameter 'q' to $options['script'] in the returned URL. When deploying
 *     Drupal on a web server that cannot be configured to automatically find
 *     index.php, then hook_url_outbound_alter() can be implemented to force
 *     this value to 'index.php'.
 *   - 'entity_type': The entity type of the object that called url(). Only set if
 *     url() is invoked by entity_uri().
 *   - 'entity': The entity object (such as a node) for which the URL is being
 *     generated. Only set if url() is invoked by entity_uri().
 *
 * @return
 *   A string containing a URL to the given path.
 */
function url($path = NULL, array $options = array())
{
	// Merge in defaults.
	$options += array(
		'fragment' => '', 
		'query' => array(), 
		'absolute' => FALSE, 
		'alias' => FALSE, 
		'prefix' => ''
	);
	
	if (!isset($options['external']))
	{
		// Return an external link if $path contains an allowed absolute URL. Only
		// call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
		// before any / ? or #. Note: we could use url_is_external($path) here, but
		// that would require another function call, and performance inside url() is
		// critical.
		$colonpos = strpos($path, ':');
		$options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && strip_dangerous_protocols($path) == $path);
	}
	
	// Preserve the original path before altering or aliasing.
	$original_path = $path;
	
	// Allow other modules to alter the outbound URL and options.
	Moduler::alter('url_outbound', $path, $options, $original_path);
	
	if (isset($options['fragment']) && $options['fragment'] !== '')
	{
		$options['fragment'] = '#' . $options['fragment'];
	}
	
	if ($options['external'])
	{
		// Split off the fragment.
		if (strpos($path, '#') !== FALSE)
		{
			list($path, $old_fragment) = explode('#', $path, 2);
			
			// If $options contains no fragment, take it over from the path.
			if (isset($old_fragment) && !$options['fragment'])
			{
				$options['fragment'] = '#' . $old_fragment;
			}
		}
		
		// Append the query.
		if ($options['query'])
		{
			$path .= (strpos($path, '?') !== FALSE ? '&' : '?') . build_query_string($options['query']);
		}
		
		if (isset($options['https']) && Storage::get('https', FALSE))
		{
			if ($options['https'] === TRUE)
			{
				$path = str_replace('http://', 'https://', $path);
			}
			elseif ($options['https'] === FALSE)
			{
				$path = str_replace('https://', 'http://', $path);
			}
		}
		
		// Reassemble.
		return $path . $options['fragment'];
	}
	
	$base_url = Config::baseUrl();
	
	// The base_url might be rewritten from the language rewrite in domain mode.
	if (!isset($options['base_url']))
	{
		$options['base_url'] = $base_url;
		
		/*
		if (isset($options['https']) && Storage::get('https', FALSE))
		{
			if ($options['https'] === TRUE)
			{
				$options['base_url'] = $base_secure_url;
				$options['absolute'] = TRUE;
			}
			elseif ($options['https'] === FALSE)
			{
				$options['base_url'] = $base_insecure_url;
				$options['absolute'] = TRUE;
			}
		}
		else
		{
			$options['base_url'] = $base_url;
		}
		*/
	}
	
	// The special path '<front>' links to the default front page.
	if ($path == '<front>')
	{
		$path = '';
	}
	elseif (!empty($path) && !$options['alias'])
	{
		/*
		$language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : '';
		$alias = drupal_get_path_alias($original_path, $language);
		
		if ($alias != $original_path)
		{
			$path = $alias;
		}
		*/
	}
	
	$base = $options['absolute'] ? $options['base_url'] . '/' : base_path();
	$prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
	
	// With Clean URLs.
	if (!empty($GLOBALS['conf']['clean_url']))
	{
		$path = encode_path($prefix . $path);
		if ($options['query'])
		{
			return $base . $path . '?' . build_query_string($options['query']) . $options['fragment'];
		}
		else
		{
			return $base . $path . $options['fragment'];
		}
	}
	else
	{
		$path = $prefix . $path;
		$query = array();
		
		if (!empty($path))
		{
			$query['q'] = $path;
		}
		
		if ($options['query'])
		{
			// We do not use array_merge() here to prevent overriding $path via query
			// parameters.
			$query += $options['query'];
		}
		
		$query = $query ? ('?' . build_query_string($query)) : '';
		$script = isset($options['script']) ? $options['script'] : '';
		
		return $base . $script . $query . $options['fragment'];
	}
}

/**
 * Return TRUE if a path is external to Drupal (e.g. http://example.com).
 *
 * If a path cannot be assessed by Drupal's menu handler, then we must
 * treat it as potentially insecure.
 *
 * @param $path
 *   The internal path or external URL being linked to, such as "node/34" or
 *   "http://example.com/foo".
 * @return
 *   Boolean TRUE or FALSE, where TRUE indicates an external path.
 */
function url_is_external($path)
{
	$colonpos = strpos($path, ':');
	// Only call the slow strip_dangerous_protocols() if $path contains a
	// ':' before any / ? or #.
	return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && strip_dangerous_protocols($path) == $path;
}

/**
 * Encodes a Drupal path for use in a URL.
 *
 * For aesthetic reasons slashes are not escaped.
 *
 * Note that url() takes care of calling this function, so a path passed to that
 * function should not be encoded in advance.
 *
 * @param $path
 *   The Drupal path to encode.
 */
function encode_path($path)
{
	return str_replace('%2F', '/', rawurlencode($path));
}

/**
 * Parse an array into a valid, rawurlencoded query string.
 *
 * This differs from http_build_query() as we need to rawurlencode() (instead of
 * urlencode()) all query parameters.
 *
 * @param $query
 *   The query parameter array to be processed, e.g. $_GET.
 * @param $parent
 *   Internal use only. Used to build the $query array key for nested items.
 *
 * @return
 *   A rawurlencoded string which can be used as or appended to the URL query
 *   string.
 *
 * @see drupal_get_query_parameters()
 * @ingroup php_wrappers
 */
function build_query_string(array $query, $parent = '')
{
	$params = array();
	
	foreach ($query as $key => $value)
	{
		$key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
		
		// Recurse into children.
		if (is_array($value))
		{
			$params[] = build_query_string($value, $key);
		}
		// If a query parameter value is NULL, only append its key.
		elseif (!isset($value))
		{
			$params[] = $key;
		}
		else
		{
			// For better readability of paths in query strings, we decode slashes.
			$params[] = $key . '=' . str_replace('%2F', '/', rawurlencode($value));
		}
	}
	
	return implode('&', $params);
}

/**
 * Processes an HTML attribute value and ensures it does not contain an URL
 * with a disallowed protocol (e.g. javascript:)
 *
 * @param $string
 *   The string with the attribute value.
 * @param $decode
 *   Whether to decode entities in the $string. Set to FALSE if the $string
 *   is in plain text, TRUE otherwise. Defaults to TRUE.
 * @return
 *   Cleaned up and HTML-escaped version of $string.
 */
function filter_xss_bad_protocol($string, $decode = TRUE)
{
	static $allowed_protocols;
	if (!isset($allowed_protocols))
	{
		$allowed_protocols = array_flip(Storage::get('filter_allowed_protocols', array('http', 'https',	'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal', 'rtsp')));
	}
	
	// Get the plain text representation of the attribute value (i.e. its meaning).
	if ($decode)
	{
		$string = decode_entities($string);
	}
	
	// Iteratively remove any invalid protocol found.
	do
	{
		$before = $string;
		$colonpos = strpos($string, ':');
		if ($colonpos > 0)
		{
			// We found a colon, possibly a protocol. Verify.
			$protocol = substr($string, 0, $colonpos);
			// If a colon is preceded by a slash, question mark or hash, it cannot
			// possibly be part of the URL scheme. This must be a relative URL,
			// which inherits the (safe) protocol of the base document.
			if (preg_match('![/?#]!', $protocol))
			{
				break;
			}
			// Per RFC2616, section 3.2.3 (URI Comparison) scheme comparison must be case-insensitive
			// Check if this is a disallowed protocol.
			if (!isset($allowed_protocols[strtolower($protocol)]))
			{
				$string = substr($string, $colonpos + 1);
			}
		}
	} while ($before != $string);
	return check_plain($string);
}

/**
 * base_path()
 *
 * Returns the base path for the site.
 * This is useful for rendering links so that a page doesn't have to "know where it is"
 *
 * ie. a link doesn't have to be represented as ../../assets/images/logo.png
 *
 * @return
 */
function base_path()
{	
	return Config::basePath();
}

/**
 * Strips dangerous protocols (e.g. 'javascript:') from a URI and encodes it for output to an HTML attribute value.
 *
 * @param $uri
 *   A plain-text URI that might contain dangerous protocols.
 *
 * @return
 *   A URI stripped of dangerous protocols and encoded for output to an HTML
 *   attribute value. Because it is already encoded, it should not be set as a
 *   value within a $attributes array passed to drupal_attributes(), because
 *   drupal_attributes() expects those values to be plain-text strings. To pass
 *   a filtered URI to drupal_attributes(), call
 *   drupal_strip_dangerous_protocols() instead.
 *
 * @see drupal_strip_dangerous_protocols()
 */
function check_url($uri)
{
	return check_plain(strip_dangerous_protocols($uri));
}

/**
 * page_header()
 * 
 */
function page_header()
{
	header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
	header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
	header("Cache-Control: store, no-cache, must-revalidate");
	header("Cache-Control: post-check=0, pre-check=0", FALSE);
	header("X-Powered-By: JohnsonTech, LLC");
}

/**
 * Since $_SERVER['REQUEST_URI'] is only available on Apache, we
 * generate an equivalent using other environment variables.
 */
function request_uri()
{
	if (isset($_SERVER['REQUEST_URI']))
	{
		$uri = $_SERVER['REQUEST_URI'];
	}
	else
	{
		if (isset($_SERVER['argv']))
		{
			$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0];
		}
		elseif (isset($_SERVER['QUERY_STRING']))
		{
			$uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
		}
		else
		{
			$uri = $_SERVER['SCRIPT_NAME'];
		}
	}
	
	// Prevent multiple slashes to avoid cross site requests via the FAPI.
	$uri = '/' . ltrim($uri, '/');
	
	return $uri;
}

/**
 * Return the URI of the referring page.
 */
function referer_uri()
{
	if (isset($_SERVER['HTTP_REFERER']))
	{
		return $_SERVER['HTTP_REFERER'];
	}
	else 
	{
		return '';
	}
}

/**
 * a()
 *
 * give a $link array, this function outputs a proper <a> tag
 *
 * @param mixed $link
 * @return
 */
function a($link)
{
	$url = '';
	if (!empty($link['#href']))
	{
		$url = valid_url($link['#href']);
	}
	
	return '<a ' . (!empty($url) ? 'href="' . check_plain($url) . '" ' : '') . 'title="' . (empty($link['#title']) ? '' : check_plain($link['#title'])) . '"' . (empty($link['#attributes']) ? '' : attributes($link['#attributes'])) . '>' . check_plain($link['#anchor']) . '</a>' . "\n";
}

/**
 * html_safe()
 *
 * Filters text to make sure that it is safe to include in HTML
 *
 * @param mixed $text
 * @return
 */
function check_plain($text)
{
	return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}

/**
 * krumo_ob()
 *
 * This function is useful for debugging (ie. displaying variables to the page, etc.)
 *
 * This function will only work if DEBUG is defined as TRUE in the main index.php file
 *
 * @param mixed $object
 * @return
 */
function krumo_ob($object)
{
	ob_start();
	krumo($object);
	$output = ob_get_contents();
	ob_end_clean();
	return $output;
}

/**
 * debug()
 *
 * This function formats and prints an object/string/array in "pretty" way to the system messages area
 *
 * @param mixed $object
 * @return void
 */
function debug($object)
{
	if (defined('DEBUG') && DEBUG === TRUE)
	{
		$output = krumo_ob($object);
		
		Athena::setMessage($output);
		return;
	}
	
	ob_start();
	var_dump($object);
	//print ('<br /><strong>Called from <em>' . xdebug_call_file() . ':' . xdebug_call_function() . ' line ' . xdebug_call_line() . '</em></strong>');
	print('<br />----------------------------------------------------------------------------<br />');
	$output = ob_get_contents();
	ob_end_clean();
	Athena::setMessage('<pre>' . $output . '</pre>');
}

/**
 * system_element_children()
 *
 * This function returns any children elements from any array that do not have keys in the array
 * that begin with a # sign because those elements will be configuration variables for the represented object
 *
 * @param mixed $elements
 * @return
 */
function element_children($element)
{
	return array_filter(array_keys((array) $element), 'attribute_filter');
}

/**
 * attribute_filter()
 *
 * Helper function for determining if array obj is a #attribute or an element
 *
 * @param mixed $attr
 * @return
 */
function attribute_filter($key)
{
	return !isset($key[0]) || $key[0] != '#';
}

/**
 * valid_email()
 *
 * Validates email addresses
 *
 * @param mixed $email
 * email address
 *
 * @return
 * TRUE if is valid, FALSE if not
 */
function valid_email($email)
{
	return preg_match("/^\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b$/", $email);
}

/**
 * valid_url()
 *
 * checks to see if a URL is valid. This function allows URLs of the form:
 *
 * http://www.google.com
 * google.com
 * /index.php
 *
 * @param mixed $url
 * the URL
 *
 * @return
 * returns the URL if valid, else FALSE
 */
function valid_url($url)
{
	if (!preg_match("/^(((ht|f)tps?:\/\/)|(www.))[a-zA-Z0-9_\-.:#\/~?]+$/", $url))
	{
		if (!preg_match("/^([a-zA-Z0-9_%-]*\.[a-z]{2,4})(\.[a-z]{2})?((\/[a-zA-Z0-9_%-]*)+)?(\.[a-z]*)?/", $url))
		{
			$aUrl = base_path() . ltrim($url, '/');
			if (!preg_match("/^((\/[a-zA-Z0-9_%-]*)+)(\.[a-z]*)?/", $aUrl))
			{
				return FALSE;
			}
			else 
			{
				return $aUrl;
			}
		}
	}
	
	return $url;
}

/**
 * Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
 *
 * As $_SERVER['HTTP_HOST'] is user input, ensure it only contains characters
 * allowed in hostnames.  See RFC 952 (and RFC 2181). $_SERVER['HTTP_HOST'] is
 * lowercased.
 *
 * @return
 * TRUE if only containing valid characters, or FALSE otherwise.
 */
function valid_http_host($host)
{
	return preg_match('/^\[?(?:[a-z0-9-:\]_]+\.?)+$/', $host);
}

/**
 * Converts a PHP variable into its Javascript equivalent.
 *
 * We use HTML-safe strings, i.e. with <, > and & escaped.
 */
function php_to_js($var)
{
	switch (gettype($var))
	{
		case 'boolean' :
			return $var ? 'true' : 'false'; // Lowercase necessary!
		case 'integer' :
		case 'double' :
			return $var;
		case 'resource' :
		case 'string' :
			return '"' . str_replace(array(
				"\r", "\n", "<", ">", "&"
			), array(
				'\r', '\n', '\x3c', '\x3e', '\x26'
			), addslashes($var)) . '"';
		case 'array' :
			// Arrays in JSON can't be associative. If the array is empty or if it
			// has sequential whole number keys starting with 0, it's not associative
			// so we can go ahead and convert it as an array.
			if (empty($var) || array_keys($var) === range(0, sizeof($var) - 1))
			{
				$output = array();
				foreach ($var as $v)
				{
					$output[] = php_to_js($v);
				}
				
				return '[ ' . implode(', ', $output) . ' ]';
			}
		// Otherwise, fall through to convert the array as an object.
		case 'object' :
			$output = array();
			foreach ($var as $k => $v)
			{
				$output[] = php_to_js(strval($k)) . ': ' . php_to_js($v);
			}
			
			return '{ ' . implode(', ', $output) . ' }';
		default :
			return 'null';
	}
}

/**
 * site_name()
 *
 * The name of the site
 *
 * @return
 */
function site_name()
{
	return 'BugZapp';
}

/**
 * system_page_title()
 *
 * sets and gets the title of the current page
 *
 * @param mixed $title
 * @return
 */
function page_title($title = null)
{
	static $page_title = '';
	
	if (isset($title))
	{
		$page_title = $title;
	}
	
	return $page_title;
}

/**
 * site_logo()
 *
 * returns the <img> tag for the site logo
 *
 * @return
 */
function site_logo()
{
	return '<img alt="' . site_name() . ' Logo" src="' . base_path() . 'assets/images/logo.png" />';
}
